﻿using SkiaSharp;
using Svg.Skia;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Media.Imaging;

namespace LeonCad.Core.Ribbons.Extension;

internal static class RibbonConverExtension
{
    /// <summary>
    /// 加载svg图片
    /// </summary>
    /// <param name="stream"></param>
    /// <param name="kImageInfo"></param>
    /// <returns></returns>
    public static BitmapImage? ConvertSvgToBitmapImage(this Stream stream, SKImageInfo kImageInfo) {
        var svg = new SKSvg();
        svg.Load(stream);
        if (svg.Picture == null)
            return null;

        using var bitmap = new SKBitmap((int)svg.Picture.CullRect.Width, (int)svg.Picture.CullRect.Height);
        using var canvas = new SKCanvas(bitmap);
        canvas.Clear(SKColors.Transparent);
        canvas.DrawPicture(svg.Picture);
        // 将 SKBitmap 转换为 Bitmap


        using var resizedBitmap = bitmap.Resize(kImageInfo, SKFilterQuality.High);
        // 将 SKBitmap 转换为 BitmapImage
        using var image = SKImage.FromBitmap(resizedBitmap);
        using var data = image.Encode(SKEncodedImageFormat.Png, 100);
        var stream2 = data.AsStream();
        var bitmapImage = new BitmapImage();
        bitmapImage.BeginInit();
        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
        bitmapImage.StreamSource = stream2;
        bitmapImage.EndInit();
        bitmapImage.Freeze();

        return bitmapImage;
    }


    // Bitmap --> BitmapImage
    internal static BitmapImage? BitmapToBitmapImage(this System.Drawing.Bitmap bitmap)
    {
        if (bitmap == null)
            return null;
        using MemoryStream stream = new();
        bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png); // 坑点：格式选Bmp时，不带透明度

        stream.Position = 0;
        BitmapImage result = new BitmapImage();
        result.BeginInit();
        // According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed."
        // Force the bitmap to load right now so we can dispose the stream.
        result.CacheOption = BitmapCacheOption.OnLoad;
        result.StreamSource = stream;
        result.EndInit();
        result.Freeze();
        bitmap.Dispose();
        return result;
    }
    /// <summary>
    /// 程序集目录下的子文件夹是否包含配置文件
    /// </summary>
    /// <param name="dirFullName">搜索的文件目录</param>
    /// <param name="searchName">搜索的文件名</param>
    /// <param name="path">文件路径</param>
    /// <returns>是否存在</returns>
    public static bool DirExists(this string dirFullName, string searchName, out string path)
    {
        foreach (var dir in System.IO.Directory.GetDirectories(dirFullName))
        {
            path = System.IO.Path.Combine(dir, searchName);
            if (System.IO.File.Exists(path))
                return true;
            else
            {
                if (DirExists(dir, searchName, out path))
                    return true;
            }
        }
        path = string.Empty;
        return false;
    }
}

internal static class IEnumerableExtensions
{
    /// <summary>
    /// 从序列中返回不同的元素
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <typeparam name="V">键类型</typeparam>
    /// <param name="source">要从中删除重复元素的序列</param>
    /// <param name="keySelector">键选择器的委托</param>
    /// <param name="comparer">相等比较器</param>
    /// <returns>不同元素的序列</returns>
    /// <example><code><![CDATA[
    /// var s=new []{ new { ID = 1, Name = "LDP"}, new { ID = 2, Name = "ldp"} };
    /// var res = s.Distinct(p => p.Name, StringComparer.CurrentCultureIgnoreCase).ToArray();
    /// ]]></code></example>
    public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector, IEqualityComparer<V>? comparer = default)
    {
        return source.Distinct(new CommonEqualityComparer<T, V>(keySelector, comparer));
    }
    /// <summary>
    /// 从序列中返回不同的元素
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="source">要从中删除重复元素的序列</param>
    /// <param name="comparer">相等方法的委托</param>
    /// <param name="getHashCode">对象哈希方法的委托</param>
    /// <returns>不同元素的序列</returns>
    /// <example><code><![CDATA[
    /// var p=new Point[]{ new Point(5,8), new Point(6,8), new Point(10,8), new Point(15,8) };
    /// var s = points.Distinct((x, y) => { return x.X - y.X <= 1; }).ToArray();
    /// ]]></code></example>
    public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source, Func<T, T, bool> comparer, Func<T, int>? getHashCode = default)
    {
        return source.Distinct(new ObjectComparer<T>(comparer, getHashCode));
    }

    public static IEnumerable<T> Union<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<T, T, bool> comparer)
    {
        return first.Union(second, new ObjectComparer<T>(comparer, null));
    }
    public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TSource, bool> comparer)
    {
        return first.Intersect(second, new ObjectComparer<TSource>(comparer, null));
    }

    internal class CommonEqualityComparer<T, V> : IEqualityComparer<T>
    {
        private readonly Func<T, V> keySelector;
        private readonly IEqualityComparer<V> comparer;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="keySelector">键选择的委托</param>
        /// <param name="comparer">相等比较器</param>
        public CommonEqualityComparer(Func<T, V> keySelector, IEqualityComparer<V>? comparer = default)
        {
            this.keySelector = keySelector;
            this.comparer = comparer ?? EqualityComparer<V>.Default;
        }

        public bool Equals(T x, T y) => comparer.Equals(keySelector(x), keySelector(y));
        public int GetHashCode(T obj) => comparer.GetHashCode(keySelector(obj));
    }

    internal class ObjectComparer<T> : IEqualityComparer<T>
    {
        private readonly Func<T, T, bool> equalFunc;
        private readonly Func<T, int> getHashCode;
        public ObjectComparer(Func<T, T, bool> equalFunc, Func<T, int>? getHashCode)
        {
            this.equalFunc = equalFunc;
            this.getHashCode = getHashCode ?? new Func<T, int>(obj => { return 0; });
        }
        public bool Equals(T x, T y) => equalFunc(x, y);

        public int GetHashCode(T obj) => getHashCode(obj);
    }
}